1 /*
2  * Collie - An asynchronous event-driven network framework using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd 
5  *
6  * Developer: putao's Dlang team
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 module collie.codec.http.server.websocket;
12 
13 import std.socket;
14 import std.exception;
15 
16 import std.experimental.allocator.gc_allocator;
17 
18 import kiss.container.Vector;
19 import kiss.logger;
20 
21 import collie.codec.http.httpmessage;
22 import collie.codec.http.errocode;
23 import collie.codec.http.codec.wsframe;
24 import collie.codec.http.headers;
25 import collie.codec.http.httptansaction;
26 import collie.codec.http.codec.httpcodec;
27 import collie.utils.memory;
28 import collie.codec.http.server;
29 
30 
31 abstract class IWebSocket : RequestHandler
32 {	
33 	this(){
34 	}
35 	
36 	pragma(inline)
37 		final bool ping(ubyte[] data)
38 	{
39 		return sendFrame(OpCode.OpCodePing,data);
40 	}
41 	
42 	pragma(inline)
43 		final bool sendText(string text)
44 	{
45 		return sendFrame(OpCode.OpCodeText,cast(ubyte[])text);
46 	}
47 	
48 	pragma(inline)
49 		final bool sendBinary(ubyte[] data)
50 	{
51 		return sendFrame(OpCode.OpCodeBinary,data);
52 	}
53 	
54 	pragma(inline)
55 		final bool close(ubyte[] data = null)
56 	{
57 		return sendFrame(OpCode.OpCodeClose,data);
58 	}
59 	
60 	pragma(inline,true)
61 		final @property Address remoteAdress()
62 	{
63 		return _addr;
64 	}
65 
66     void onClose(ubyte[] data);
67     void onText(string frame);
68     void onPong(ubyte[] frame);
69     void onBinary(ubyte[] frame);
70 	void onErro(HTTPErrorCode code);
71 protected:
72 	final override void onResquest(HTTPMessage headers) nothrow{}
73 	final override void onBody(const ubyte[] data) nothrow{}
74 	final override void onEOM() nothrow{}
75 	final override void requestComplete() nothrow{}
76 	final override void onError(HTTPErrorCode code) nothrow {
77 		try {
78         	if(code != HTTPErrorCode.TIME_OUT)
79 		    _downstream = null;
80 			onErro(code);
81 		} catch(Exception) {}
82 	}
83 	override bool onUpgtade(CodecProtocol protocol,HTTPMessage msg) nothrow{
84 		//_addr = msg.clientAddress();
85 		collectException(msg.clientAddress(),_addr);
86 		if(protocol == CodecProtocol.WEBSOCKET)
87 			return true;
88 		return false;
89 	}
90 	
91 	override void onFrame(ref WSFrame wsf) nothrow{
92 		if(wsf.isControlFrame){
93 			switch(wsf.opCode){
94 				case OpCode.OpCodePing:
95 					collectException(sendFrame(OpCode.OpCodePong,wsf.data));
96 					break;
97 				case OpCode.OpCodePong:
98 					collectException(onPong(wsf.data));
99 					break;
100 				case OpCode.OpCodeClose:
101 					collectException((){sendFrame(OpCode.OpCodeClose,wsf.data);
102 							onClose(wsf.data);}());
103 					break;
104 				default:
105 					break;
106 			}
107 		} else {
108 			if(wsf.parentCode == OpCode.OpCodeText){
109 				collectException((){
110 					_text ~= wsf.data;
111 					if(wsf.isFinalFrame){
112 						onText(cast(string)(_text));
113 						_text = null;
114 					}
115 					}());
116 			} else {
117 				collectException((){
118 					_binary ~= wsf.data;
119 					if(wsf.isFinalFrame){
120 						onBinary(_binary);
121 						_binary = null;
122 					}
123 					}());
124 			}
125 		}
126 	}
127 
128 	bool sendFrame(OpCode code,ubyte[] data)
129 	{
130 		if(!_downstream) return false;
131 			_downstream.sendWsData(code,data);
132 		return true;
133 	}
134 
135 	deprecated("Incorrect spelling. Using sendFrame instead.")
136  	bool sendFarme(OpCode code,ubyte[] data)
137  	{
138 		return sendFrame(code, data);
139 	}
140 
141 package:
142 	ubyte[] _text;
143 	ubyte[] _binary;
144     Address _addr;
145 }